﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;

namespace RzCorportativo.DataAccess
{

    /// <summary>
    /// Classe responsável por realizar operações em Transação no banco de dados
    /// </summary>
    public sealed class Transaction
    {
        /// <summary>
        /// Construtor padrão
        /// </summary>
        private Transaction() { }

        /// <summary>
        /// Exception ocorrida na operação
        /// </summary>
        private Exception Error { get; set; }

        /// <summary>
        /// Evento que ocorre quando uma ação é completada
        /// </summary>
        /// <param name="action">método passado pelo usuário que irá executar uma ação customizada</param>
        public void OnCompleted(Action action)
        {
            if (action != null)
                action();
        }

        /// <summary>
        /// Método chamado se somente ocorrer um erro ou exception na operação
        /// </summary>
        /// <param name="action">ação customizada do usuário que irá executar quando ouver um erro, para esta ação será passada a instancia da exception ocorrida</param>
        /// <returns>instancia corrente da classe de transações</returns>
        public Transaction OnError(Action<Exception> action)
        {
            if (this.Error == null)
                return this;
            else if (this.Error != null && action != null)
                action(this.Error);
            return this;
        }

        /// <summary>
        /// Método chamado somente se não ocorrer nenhum erro na operação
        /// </summary>
        /// <param name="action">método customizado do usuário que será executado</param>
        /// <returns>instancia corrente da classe de transações</returns>
        public Transaction OnSuccess(Action action)
        {
            if (this.Error != null)
                return this;
            else if (action != null)
                action();
            return this;
        }

        /// <summary>
        /// Método que inicia uma transação, no banco de dados e se não houverem erros, ele é responsável por comitar a ação
        /// se houver algum erro a transação é cancelada no mesmo momento
        /// </summary>
        /// <param name="action">ação que irá ocorrer na transação</param>
        /// <returns>retorna a instancia corrente da transação</returns>
        public static Transaction Begin(Func<SistemaCurricularEntities, bool> action)
        {
            bool saveChanges = false;
            Transaction transaction = new Transaction();
            if (action == null)
                throw new NullReferenceException("ação de execução não pode ser nula");
            try
            {
                SistemaCurricularEntities entity = new SistemaCurricularEntities();
                entity.SavingChanges += new EventHandler((obj, e) =>
                {
                    saveChanges = true;
                });
                using (TransactionScope tran = new TransactionScope())
                {
                    if (action(entity))
                    {
                        bool success = true;
                        if (!saveChanges)
                            success = entity.SaveChanges() > 0;
                        if (success)
                            tran.Complete();
                    }
                }
            }
            catch (Exception ex)
            {
                transaction.Error = ex;
            }
            return transaction;
        }

    }
}
